#!/usr/bin/python
import twitter
import config
import logging
import traceback
import xmpp
from mylocale import gettext
from utils import Utils
from time import time
from StringIO import StringIO
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.runtime.apiproxy_errors import CapabilityDisabledError, DeadlineExceededError
from db import Db, GoogleUser, TwitterUser, IdList, MODE_HOME, MODE_LIST, MODE_MENTION, MODE_DM

class cron_handler(webapp.RequestHandler):
  def get(self, cron_id):
    try:
      cron_id = int(cron_id)
      data = GoogleUser.get_all(shard=cron_id)
      for u in data:
        jid = u.key().name()
        flag = xmpp.get_presence(jid)
        if flag:
          try:
            self.process(u)
          except CapabilityDisabledError:
            xmpp.send_presence(jid, presence_show=xmpp.PRESENCE_SHOW_AWAY)
          else:
            xmpp.send_presence(jid)
    except DeadlineExceededError:
      pass

  def process(self, google_user):
    time_delta = int(time()) - google_user.last_update
    if time_delta < google_user.interval * 60 - 30:
      return
    _ = lambda x: gettext(x, locale=google_user.locale)
    twitter_user = TwitterUser.get_by_twitter_name(google_user.enabled_user, google_user.jid)
    if twitter_user is None:
      google_user.enabled_user = ''
      Db.set_datastore(google_user)
      return
    api = twitter.Api(consumer_key=config.OAUTH_CONSUMER_KEY,
                      consumer_secret=config.OAUTH_CONSUMER_SECRET,
                      access_token_key=twitter_user.access_token_key,
                      access_token_secret=twitter_user.access_token_secret)
    try:
      self._user = api.verify_credentials()
      if not self._user or 'screen_name' not in self._user:
        raise twitter.TwitterError
    except twitter.TwitterError:
      google_user.retry += 1
      if google_user.retry >= config.MAX_RETRY:
        GoogleUser.disable(jid=google_user.jid)
        xmpp.send_message(google_user.jid, _('NO_AUTHENTICATION'))
      else:
        Db.set_cache(google_user)
      return
    finally:
      if google_user.retry > 0:
        google_user.retry = 0
        Db.set_cache(google_user)
    if twitter_user.twitter_name != self._user['screen_name']:
      twitter_user.twitter_name = self._user['screen_name']
      Db.set_cache(twitter_user)
      google_user.enabled_user = self._user['screen_name']
      Db.set_cache(google_user)
    self._utils = Utils(google_user.jid)
    self._utils.allow_duplicate = False
    at_username = '@' + google_user.enabled_user
    statuses_id = []
    mention_statuses = []
    list_content = ''
    dm_content = ''
    mention_content = ''
    home_content = ''

    if google_user.display_timeline & MODE_DM:
      try:
        statuses = api.get_direct_messages(since_id=google_user.last_dm_id)
        if statuses and statuses[0]['id'] > google_user.last_dm_id:
          google_user.last_dm_id = statuses[0]['id']
        dm_content = self._utils.parse_statuses(statuses)
      except twitter.TwitterInternalServerError:
        pass
      except BaseException:
        err = StringIO()
        traceback.print_exc(file=err)
        logging.error(google_user.jid + ' DM:\n' + err.getvalue())

    if google_user.display_timeline & MODE_LIST:
      try:
        list_statuses = api.get_list_statuses(user=google_user.list_user, id=google_user.list_id, since_id=google_user.last_list_id)
        if list_statuses:
          if list_statuses[0]['id'] > google_user.last_list_id:
            google_user.last_list_id = list_statuses[0]['id']
          if google_user.display_timeline & MODE_MENTION:
            for i in range(len(list_statuses) - 1, -1, -1):
              x = list_statuses[i]
              statuses_id.append(x['id'])
              if at_username in x['text']:
                mention_statuses.append(x)
                del list_statuses[i]
          list_content = self._utils.parse_statuses(list_statuses, filter_self=True)
      except twitter.TwitterInternalServerError:
        pass
      except BaseException, e:
        if 'Not found' not in e.message:
          err = StringIO()
          traceback.print_exc(file=err)
          logging.error(google_user.jid + ' List:\n' + err.getvalue())

    if google_user.display_timeline & MODE_HOME:
      try:
        home_statuses = api.get_home_timeline(since_id=google_user.last_msg_id)
        if home_statuses:
          if home_statuses[0]['id'] > google_user.last_msg_id:
            google_user.last_msg_id = home_statuses[0]['id']
          if google_user.display_timeline & MODE_MENTION:
            for i in range(len(home_statuses) - 1, -1, -1):
              x = home_statuses[i]
              if x['id'] not in statuses_id:
                statuses_id.append(x['id'])
                if at_username in x['text']:
                  mention_statuses.append(x)
                  del home_statuses[i]
          home_content = self._utils.parse_statuses(home_statuses, filter_self=True)
      except twitter.TwitterInternalServerError:
        pass
      except BaseException, e:
        if 'Not found' not in e.message:
          err = StringIO()
          traceback.print_exc(file=err)
          logging.error(google_user.jid + ' Home:\n' + err.getvalue())

    if google_user.display_timeline & MODE_MENTION:
      try:
        tmp_mention_statuses = api.get_mentions(since_id=google_user.last_mention_id)
        if tmp_mention_statuses:
          if tmp_mention_statuses[0]['id'] > google_user.last_mention_id:
            google_user.last_mention_id = tmp_mention_statuses[0]['id']
          for x in tmp_mention_statuses:
            if x['id'] not in statuses_id:
              mention_statuses.append(x)
              statuses_id.append(x['id'])
        mention_statuses.sort(cmp=lambda x, y: cmp(x['id'], y['id']))
        mention_content = self._utils.parse_statuses(mention_statuses, reverse=False, filter_self=True)
      except twitter.TwitterInternalServerError:
        pass
      except BaseException:
        err = StringIO()
        traceback.print_exc(file=err)
        logging.error(google_user.jid + ' Mention:\n' + err.getvalue())

    IdList.flush(google_user.jid)

    google_user.last_update = int(time())
    if Db.set_datastore(google_user):
      if dm_content:
        xmpp.send_message(google_user.jid, _('DIRECT_MESSAGES') + '\n\n' + dm_content)
      if mention_content:
        xmpp.send_message(google_user.jid, _('MENTIONS') + '\n\n' + mention_content)
      if list_content:
        xmpp.send_message(google_user.jid, _('LIST') % (google_user.list_user + '/' + google_user.list_name) + '\n\n' + list_content)
      if home_content:
        xmpp.send_message(google_user.jid, _('TIMELINE') + '\n\n' + home_content)


if __name__ == "__main__":
  application = webapp.WSGIApplication([('/cron(\d+)', cron_handler)])
  run_wsgi_app(application)
